const defaults = {
	timeout: 0// 超时的时间
}

// 拦截器
class InterceptorManager {
	constructor() {
		this.handlers = [];
	}
	
	use(fulfilled, rejected) {
		// 1- 将成功回调与失败回调生成一个对象放置到数组handlers中
		this.handlers.push({
			fulfilled,
			rejected
		})
		// 2- 返回生成对象所在的下标
		return this.handlers.length - 1;
	}
	eject(id) {
		if (this.handlers[id]) {
			this.handlers[id] = null;
		}
	}
}

// Axios类
class Axios {
	constructor(instanceConfig) {
		// 默认配置项
		this.defaults = instanceConfig;
		this.interceptors = {
			request: new InterceptorManager(),
			response: new InterceptorManager()
		};
	}
	
	// configOrUrl:配置对象或地址
	// config:地址
	request(configOrUrl, config) {
		// 判断参数configOrUrl是否为字符串
		if (typeof configOrUrl === "string") {
			// 将接收到的参数config,作为配置项，如果config为undefined,默认为{}
			config = config || {};
			// 将配置对象中的url属性值设置为configOrUrl
			config.url = configOrUrl;
		} else {
			// 将configOrUrl作为配置对象，如果configOrUrl为undefined,默认为{}
			config = configOrUrl || {};
		}
		// 将默认配置项this.defaults,与config进行合并
		config = {
			...this.defaults,
			...config
		}
		// 设置默认请求方式
		config.method = (config.method || this.defaults.method || "get").toLowerCase();
		
		// 设置config.url
		if (config.baseURL && !config.url.startsWith("http://")) {
			config.url = config.baseURL + config.url;
		}
		
		if (config.params) {
			config.url += "?" + Object.keys(config.params).map(key => key + "=" + config.params[key]).join("&");
		}
		
		// 发送请求
		const dispatchRequest = function (config) {
			return new Promise((resolve, reject) => {
				const request = new XMLHttpRequest();
				request.timeout = config.timeout;
				request.responseType = "json";
				if (config.cancelToken) {
					config.cancelToken.cancel.then(value => {
						request.abort();// 取消请求
					})
				}
				request.open(config.method, config.url);
				if (config.data && ["post", "delete", "put", "patch"].includes(config.method)) {
					if (typeof config.data === "string") {
						request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
					} else {
						request.setRequestHeader("Content-Type", "application/json");
						config.data = JSON.stringify(config.data);
					}
				}
				request.send(config.data);
				request.onload = function () {
					resolve({
						// axios配置对象
						config,
						// 响应体
						data: request.response,
						// 响应头
						headers: request.getAllResponseHeaders(),
						// XMLHttpRequest实例
						request,
						status: request.status,
						statusText: request.statusText
					})
				}
				// 超时
				request.ontimeout = function (err) {
					reject({
						config,
						message: "timeout of " + config.timeout + "ms exceeded",
						code: "ECONNABORTED",
						name: "AxiosError",
						request,
						stack: err
					})
				}
				// 取消请求回调
				request.onabort = function () {
					reject({
						code: "ERR_CANCELED",
						message: "canceled",
						name: "CanceledError"
					})
				}
			})
			
		}
		
		
		let promise = Promise.resolve(config);
		const chains = [dispatchRequest.bind(this),undefined];
		
		// this.interceptors.request.handlers:
		// [
		//     {fulfilled:请求拦截1成功回调,rejected:undefined},
		//     {fulfilled:请求拦截2成功回调,rejected:undefined}
		// ]
		// 执行完以下代码后chains数组：
		// [
		//      fulfilled:请求拦截2成功回调,rejected:undefined,
		//      fulfilled:请求拦截1成功回调,rejected:undefined,
		//      dispatchRequest.bind(this),undefined
		// ]
		this.interceptors.request.handlers.forEach(item=>{
			if(item)
				chains.unshift(item.fulfilled,item.rejected);
		})
		
		
		
		// this.interceptors.response.handlers:
		// [
		//     {fulfilled:响应拦截1成功回调,rejected:undefined},
		//     {fulfilled:响应拦截2成功回调,rejected:undefined}
		// ]
		// 执行完以下代码后chains数组：
		// [
		//      fulfilled:请求拦截2成功回调,rejected:undefined,(完成）
		//      fulfilled:请求拦截1成功回调,rejected:undefined,
		//      dispatchRequest.bind(this),undefined
		//      fulfilled:响应拦截1成功回调,rejected:undefined，
		//      fulfilled:响应拦截2成功回调,rejected:undefined
		// ]
		this.interceptors.response.handlers.forEach(item=>{
			if(item)
				chains.push(item.fulfilled,item.rejected);
		})
		// console.log(chains.length)
		while(chains.length){// 6
			promise = promise.then(chains.shift(),chains.shift());
		}
		// promise最终：
		/*
		promise = Promise.resolve(config)
						.then(function(config){console.log(请求拦截2);return config;},rejected:undefined)
						.then(function(config){console.log(请求拦截1);return config;},rejected:undefined)
						.then(dispatchRequest.bind(this),undefined)
						.then(function(res){console.log(响应拦截1);return res},rejected:undefined)
						.then(function(res){console.log(响应拦截2);return res.data},rejected:undefined)
					
		
		
		* */
		
		return promise;
		
	}
	
	get(url, config) {
		return this({
			url,
			...config
		})
	}
	
	post(url, data, config) {
		return this({
			method: "post",
			url,
			data,
			...config
		})
	}
	
}


// createInstance返回实例（使用的axios)
function createInstance(defaultConfig) {
	const context = new Axios(defaultConfig);
	// 将Axios实例绑定到Axios.prototype.request
	const instance = Axios.prototype.request.bind(context);
	for (let key in context) {
		instance[key] = context[key];
	}
	Object.getOwnPropertyNames(Axios.prototype).forEach(key => {
		instance[key] = Axios.prototype[key];
	})
	return instance;
}

const axios = createInstance(defaults);
axios.CancelToken = function (cb) {
	this.cancel = new Promise(resolve => {
		cb(resolve);
	})
}
axios.isCancel = function (err) {
	return err.name === "CanceledError"
}
axios.all = function (promises) {
	return Promise.all(promises);
}
axios.spread = function (callback) {
	return function (arr) {
		// 成功回调函数
		// console.log(1111)
		return callback.apply(null, arr)
	}
}
export default axios;